/*  Copyright (C) 2022 Davide Faconti -  All Rights Reserved
 *
*
*   Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
*   to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
*   and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
*   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#pragma once

#include "sol/sol.hpp"
#include <fstream>
#include <iostream>
#include "behaviortree_cpp_v3/action_node.h"

namespace BT
{
std::string readFile(const std::string& filePath)
{
    std::cout << "lua file:" << filePath << std::endl;
    std::ifstream file(filePath);
    if (!file.is_open())
    {
        std::cerr << "Could not open the file: " << filePath << std::endl;
        return "";
    }

    std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    file.close();
    return content;
}

bool runLuaScript(const std::string& scriptPath)
{
    std::string scriptCont = readFile(scriptPath);
    if(scriptCont.size() == 0) return false;

    sol::state lua;
    lua.open_libraries(sol::lib::base, sol::lib::package,sol::lib::os);
    lua.set_function("myprint", [&](std::string msg)
    {
        std::cout << "myprint:" << msg << std::endl;
    });

    auto result = lua.script(scriptCont, sol::script_pass_on_error);
    if (result.valid())
    {
        std::cout << "Script executed successfully!" << std::endl;
    }
    else
    {
        sol::error err = result;
        std::cout << "Script execution failed: " << err.what() << std::endl;
        return false;
    }
    return true;
}


class ScriptNode: public SyncActionNode
{
public:
      ScriptNode(const std::string& name, const NodeConfiguration& config):SyncActionNode(name, config)
      {
        setRegistrationID("ScriptNode");
        loadExecutor();
      }

      static PortsList providedPorts()
      {
        return { InputPort<std::string>("path", "") };
      }

private:
      virtual BT::NodeStatus tick() override
      {
        auto path = getInput<std::string>("path");
        if (!path)
        {
          throw BT::RuntimeError("missing required input [message]: ", path.error());
        }
        std::cout << "lua path: " << path.value() << std::endl;

        return runLuaScript(path.value())? NodeStatus::SUCCESS : NodeStatus::FAILURE;
      }

      void loadExecutor()
      {
        std::string script;
      }

      std::string _script;
      //ScriptFunction _executor;
};


class IdleNode : public BT::StatefulActionNode
{
public:
  IdleNode(const std::string& name, const BT::NodeConfiguration& config)
    : BT::StatefulActionNode(name, config)
  {}

  static BT::PortsList providedPorts()
  {
      // amount of milliseconds that we want to sleep
      return{};
  }

  NodeStatus onStart() override
  {
      return NodeStatus::RUNNING;
  }

  /// method invoked by an action in the RUNNING state.
  NodeStatus onRunning() override
  {
      return NodeStatus::RUNNING;
  }

  void onHalted() override
  {
      std::cout << "SleepNode interrupted" << std::endl;
  }

private:
};

}
